#include "host.h"
#include <WinCrypt.h>

PubKey::PubKey()
: m_key( NULL )
, m_keyLen( 0 )
, m_e( 0 )
, m_capa( 0 ){}

PubKey::~PubKey()
{
	UnSet();
}

void PubKey::Set( BYTE* key, int len, int e, int capa )
{
	UnSet();
	m_keyLen = len;
	m_key = new BYTE[m_keyLen];
	memcpy( m_key, key, m_keyLen );

	m_e = e;
	m_capa = capa;
}

void PubKey::UnSet()
{
	delete[] m_key;
	m_key = NULL;
	m_capa = 0;
}

bool PubKey::KeyBlob( BYTE* blob, int maxLen, int* len )
{
	*len = GetKeyBlobLen();
	if( *len > maxLen )
		return false;
	blob[0] = PUBLICKEYBLOB;
	blob[1] = CUR_BLOB_VERSION;
	*(WORD*)(blob + 2) = 0;
	*(ALG_ID*)(blob + 4 ) = CALG_RSA_KEYX;
	memcpy( blob + 8, "RSA1", 4 );
	*(DWORD*)(blob + 12) = m_keyLen * 8;
	*(int*)(blob + 16) = m_e;
	memcpy( blob + 20, m_key, m_keyLen );
	return true;
}

void PubKey::SetByBlob( BYTE* blob, int capa )
{
	UnSet();
	m_keyLen = *(int*)(blob + 12) / 8;
	m_key = new BYTE[m_keyLen];
	memcpy( m_key, blob + 20, m_keyLen );
	m_e = *(int*)(blob+16);
	m_capa = capa;
}

//////////////////////////////////////////////////////////////////////////
CHosts::CHosts( void )
: m_hostCnt( 0 )
{
	memset( m_hosts, 0, sizeof( m_hosts ) );
	for( int kind = 0; kind < MAX_ARRAY; ++kind )
		_enable[kind] = false;
}

CHosts::~CHosts()
{
	for( int kind = 0; kind < MAX_ARRAY; ++kind )
	{
		if( m_hosts[kind] )
			free( m_hosts[kind] );
	}
}

int CHosts::Cmp( THostSub* hostSub1, THostSub* hostSub2, Kind kind )
{
	switch( kind )
	{
	case NAME:
	case NAME_ADDR:
		{
			int cmp = _stricmp( hostSub1->userName, hostSub2->userName );
			if( cmp != 0 ) return cmp;
			cmp = _stricmp( hostSub1->hostName, hostSub2->hostName );
			if( cmp != 0 || kind == NAME ) return cmp;
		}
	case ADDR:
		if( hostSub1->addr > hostSub2->addr ) return 1;
		if( hostSub1->addr < hostSub2->addr ) return -1;
		if( hostSub1->portNum > hostSub2->portNum ) return 1;
		if( hostSub1->portNum < hostSub2->portNum ) return -1;
		return 0;
	}
	return -1;
}

THost* CHosts::Search( Kind kind, THostSub* hostSub, int* insertIndex /* = NULL */ )
{
	int tmpIndex = 0;
	if( insertIndex == NULL )
		insertIndex = &tmpIndex;
	
	int min = 0;
	int max = m_hostCnt - 1;
	while( min <= max )
	{
		*insertIndex = (min+max)/2;
		int cmp = Cmp( hostSub, &m_hosts[kind][*insertIndex]->hostSub, kind );
		if( cmp == 0 ) return m_hosts[kind][*insertIndex];
		if( cmp > 0 ) min = *insertIndex + 1;
		else max = *insertIndex - 1;
	}
	*insertIndex = min;
	return NULL;
}

bool CHosts::AddHost( THost* host )
{
	int insertIndex[MAX_ARRAY] = { 0 };;
	for( int kind = 0; kind < MAX_ARRAY; ++kind )
	{
		if( !_enable[kind] ) continue;
		if( Search( (Kind)kind, &host->hostSub, &insertIndex[kind] ) != NULL )
			return false;
	}

#define BIG_ALLOG 100
	for( int kind = 0; kind < MAX_ARRAY; ++kind )
	{
		if( !_enable[kind] ) continue;
		if( ( m_hostCnt % BIG_ALLOG ) == 0 )
		{
			THost** tmpHost = (THost**)realloc( m_hosts[kind], (m_hostCnt+BIG_ALLOG)*sizeof(THost*) );
			if( tmpHost == NULL ) return false;
			m_hosts[kind] = tmpHost;
		}
		memmove( m_hosts[kind] + insertIndex[kind] + 1, m_hosts[kind] + insertIndex[kind],
			(m_hostCnt-insertIndex[kind])*sizeof(THost*) );
		m_hosts[kind][insertIndex[kind]] = host;
	}
	host->RefCnt( 1 );
	++m_hostCnt;
	return true;
}

bool CHosts::DelHost( THost* host )
{
	int insertIndex[MAX_ARRAY] = { 0 };
	for( int kind = 0; kind < MAX_ARRAY; ++kind )
	{
		if( !_enable[kind] ) continue;
		if( NULL == Search( (Kind)kind, &host->hostSub, &insertIndex[kind] ) )
			return false;
	}
	--m_hostCnt;
	for( int kind = 0; kind < MAX_ARRAY; ++kind )
	{
		if( !_enable[kind] )  continue;
		memmove( m_hosts[kind] + insertIndex[kind], m_hosts[kind] + insertIndex[kind] + 1,
			(m_hostCnt - insertIndex[kind]) * sizeof(THost*) );
	}
	host->RefCnt( -1 );
	return true;
}

int CHosts::PriorityHostCnt( int priority, int range /* = 1 */ )
{
	int member = 0;
	for( int cnt = 0; cnt < m_hostCnt; ++cnt )
	{
		if( m_hosts[NAME][cnt]->priority > priority && m_hosts[NAME][cnt]->priority < priority + range )
			++member;
	}
	return member;
}

//////////////////////////////////////////////////////////////////////////
bool IsSameHost( THostSub *hostSub1, THostSub *hostSub2 )
{
	if ( _stricmp(hostSub1->hostName, hostSub2->hostName) )
		return	false;
	return	_stricmp(hostSub1->userName, hostSub2->userName) ? false : true;
}